﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Serialization;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace d39
{
    [Serializable]
    public class EffectType
    {
        [XmlIgnore]
        public Color Color { get; set; }

        [XmlAttribute("color")]
        public string ColorString
        {
            get { return ColorTranslator.ToHtml(Color); }
            set { Color = ColorTranslator.FromHtml(value); }
        }

        [XmlAttribute("perimeter")]
        public int PerimeterThickness { get; set; }

        [XmlIgnore]
        public Color PerimeterColor { get; set; }

        [XmlAttribute("perimeter-color")]
        public string PerimeterColorString
        {
            get { return ColorTranslator.ToHtml(PerimeterColor); }
            set { PerimeterColor = ColorTranslator.FromHtml(value); }
        }

        [XmlAttribute("perimeter-style")]
        public DashStyle PerimeterDashStyle { get; set; }

        [XmlAttribute("opacity")]
        public int Opacity { get; set; }

        [XmlAttribute("inverted")]
        public bool IsInverted { get; set; }

        [XmlAttribute("name")]
        public string Description { get; set; }

        [XmlElement("instance")]
        public List<EffectInstance> Instances { get; set; }

        [XmlAttribute("shape")]
        public EffectShape Shape { get; set; }

        public EffectType()
        {
            Color = Color.FromArgb(0, 0, 0);
            PerimeterColor = Color.FromArgb(0, 0, 0);
            PerimeterDashStyle = DashStyle.Solid;
            PerimeterThickness = 1;
            Opacity = 0;
            IsInverted = false;
            Shape = EffectShape.FilledCircle;
            Instances = new List<EffectInstance>();
        }

        [XmlIgnore]
        public Color ColorWithOpacity
        {
            get { return Color.FromArgb((Opacity * 255) / 10, Color); }
        }

        [XmlIgnore]
        public Color PerimeterColorWithOpacity
        {
            get { return Color.FromArgb((Opacity * 255) / 10, PerimeterColor); }
        }

        [XmlIgnore]
        public string CssStyle
        {
            get
            {
                var result = "background-color: " + ColorTranslator.ToHtml(Color) +
                    "; color:" + ColorTranslator.ToHtml(Color.GetContrastColor()) + "; border: " + PerimeterThickness + "px ";
                if (PerimeterDashStyle == DashStyle.Dash)
                {
                    result += "dashed";
                }
                else if (PerimeterDashStyle == DashStyle.Dot)
                {
                    result += "dotted";
                }
                else
                {
                    result += "solid";
                }
                return result + ColorTranslator.ToHtml(PerimeterColor);
            }
        }

        // The format is:
        // SXO000000T111111Piiii-D
        // S = shape char
        // X = X if inverted, missing if not
        // O = opacity (G through Q)
        // 000000 = Color
        // T111111P (optional) - perimeter thickness and color. Perimeter thickness is between 1 and 4; if a number is not in that location, then both the
        // thickness and color are omitted. P is either omitted, 8 (dashed) or 9 (dotted).
        // iiii = list of instances of the effect
        // D = description, optional
        public static EffectType FromString(string str)
        {
            var result = new EffectType();
            int end = 0;
            result.Shape = EffectShapes.FromChar(str[end++]);
            if (str[end] == 'X')
            {
                result.IsInverted = true;
                end++;
            }
            if (str[end] >= 'G' && str[end] <= 'Q')
            {
                result.Opacity = (int)str[end++] - (int)'G';
            }
            result.Color = ColorTranslator.FromHtml('#' + str.Substring(end, 6));
            end += 6;
            if (end < str.Length && str[end] >= '1' && str[end] <= '4')
            {
                result.PerimeterThickness = int.Parse(str.Substring(end, 1));
                result.PerimeterColor = ColorTranslator.FromHtml('#' + str.Substring(end + 1, 6));
                end += 7;
                if (end < str.Length && (str[end] == '8' || str[end] == '9'))
                {
                    result.PerimeterDashStyle = (str[end] == '8' ? DashStyle.Dash : DashStyle.Dot);
                    end++;
                }
            }
            else
            {
                result.PerimeterThickness = 0;
            }
            var descrStart = str.IndexOf('-', end);
            if (descrStart >= 0)
            {
                result.Description = str.Substring(descrStart + 1);
            }
            else
            {
                descrStart = str.Length;
            }
            while (end < descrStart)
            {
                result.Instances.Add(EffectInstance.Parse(result, str, end, out end));
            }
            return result;
        }
        public string ToString(UrlTweaks tweaks)
        {
            var includeDescription = tweaks.IncludeDescriptions;
            if (string.IsNullOrEmpty(Description)) includeDescription = false;
            var start = Shape.ToChar().ToString();
            if (IsInverted) start += 'X';
            if (Opacity > 0) start += (char)((int)'G' + Opacity);
            start += ColorTranslator.ToHtml(Color).Substring(1);
            if (PerimeterThickness != 0)
            {
                start += PerimeterThickness + ColorTranslator.ToHtml(PerimeterColor).Substring(1);
                if (PerimeterDashStyle == DashStyle.Dash) start += '8';
                if (PerimeterDashStyle == DashStyle.Dot) start += '9';
            }
            foreach (var instance in Instances) start += instance.ToString();
            return includeDescription ? start + "-" + Description : start;
        }
    }
}